﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using BCCommon;
using BCCommon.Enums.Chats;
using BCCommon.Exceptions;
using BCCommon.OAEnums.TeamWork;
using BCEntity.OA.TeamWork.TeamWork;
using BCEntity.OA.TeamWork.TeamWorkAttachment;
using BCEntity.OA.TeamWork.TeamWorkCategory;
using BCEntity.OA.TeamWork.TeamWorkParticipant;
using BCEntity.OA.TeamWork.TeamWorkReply;
using BCData.OA.TeamWork.TeamWork;
using BCData.OA.TeamWork.TeamWorkAttachment;
using BCData.OA.TeamWork.TeamWorkCategory;
using BCData.OA.TeamWork.TeamWorkParticipant;
using BCData.OA.TeamWork.TeamWorkReply;
using BCDto.Common;
using BCDto.Chats.Thread;
using BCDto.OA.TeamWork.TeamWork;
using BCDto.OA.TeamWork.TeamWorkReply;
using BCDto.OA.TeamWork.TeamWorkParticipant;
using BCService.Utils;
using BCDto.OA.Common;
using BCEntity.Sim.Admin.StaffOrganizationMappingRecord;
using BCData.Sim.Admin.StaffOrganizationMappingRecord;

namespace BCService.OA.TeamWork.TeamWorkService
{
    public class TeamWorkService : ITeamWorkService
    {
        private readonly IApplicationContextService applicationContextService;
        //private readonly IThreadService threadService;
        private readonly ITeamWorkData teamWorkData;
        private readonly ITeamWorkParticipantData teamWorkParticipantData;
        private readonly ITeamWorkCategoryData teamWorkCategoryData;
        private readonly ITeamWorkAttachmentData teamWorkAttachmentData;
        private readonly ITeamWorkReplyData teamWorkReplyData;
        private readonly IStaffOrganizationMappingRecordData staffOrganizationMappingRecordData;

        public TeamWorkService(IApplicationContextService applicationContextService,
            //IThreadService threadService,
            ITeamWorkData teamWorkData,
            ITeamWorkParticipantData teamWorkParticipantData,
            ITeamWorkCategoryData teamWorkCategoryData,
            ITeamWorkAttachmentData teamWorkAttachmentData,
            ITeamWorkReplyData teamWorkReplyData,
            IStaffOrganizationMappingRecordData staffOrganizationMappingRecordData)
        {
            this.applicationContextService = applicationContextService;
            //this.threadService = threadService;
            this.teamWorkData = teamWorkData;
            this.teamWorkParticipantData = teamWorkParticipantData;
            this.teamWorkCategoryData = teamWorkCategoryData;
            this.teamWorkAttachmentData = teamWorkAttachmentData;
            this.teamWorkReplyData = teamWorkReplyData;
            this.staffOrganizationMappingRecordData = staffOrganizationMappingRecordData;
        }

        #region 协同办公信息相关
        public TeamWorkDto Add(TeamWorkRequestDto requestDto)
        {
            if (requestDto.TeamWorkCategoryId == 0 && string.IsNullOrWhiteSpace(requestDto.TeamWorkCategoryCode))
            {
                throw new ArgumentException("协同办公分类和协同办公分类Code不能同时为空");
            }

            TeamWorkCategoryEntity categoryEntity;

            if (string.IsNullOrWhiteSpace(requestDto.TeamWorkCategoryCode))
            {
                categoryEntity = this.teamWorkCategoryData.GetEntity(requestDto.TeamWorkCategoryId).Result;
            }
            else
            {
                categoryEntity = this.teamWorkCategoryData.GetEntity(requestDto.TeamWorkCategoryCode).Result;
            }

            if (categoryEntity == null)
            {
                throw new ArgumentException("此协同办公分类不存在");
            }

            if (requestDto.Participants == null || !requestDto.Participants.Any())
            {
                throw new ArgumentException("请设置协同办公参与人");
            }

            if (string.IsNullOrWhiteSpace(requestDto.ReferenceNo) && categoryEntity.IsPredefined)
            {
                throw new ArgumentException("此协同办公任务缺少引用信息");
            }
            else
            {
                if (categoryEntity.IsPredefined)
                {
                    if (!long.TryParse(requestDto.ReferenceNo, out long referenceId))
                    {
                        throw new ArgumentException("此引用信息不正确");
                    }
                }
                else
                {
                    requestDto.ReferenceNo = Guid.NewGuid().ToString();
                }
            }

            List<long> participantIds = requestDto.Participants.Select(p => p.ParticipantId).ToList();

            if (!participantIds.Contains(1))
            {
                participantIds.Add(1);
            }

            if (!participantIds.Contains(applicationContextService.Admin.AdminId))
            {
                participantIds.Add(applicationContextService.Admin.AdminId);
            }

            var staffInfoList = this.staffOrganizationMappingRecordData.GetList(participantIds.ToArray()).Result;

            if (!staffInfoList.Any())
            {
                throw new ArgumentException("参与人列表未获取到任何信息");
            }

            var entity = requestDto.As<TeamWorkEntity>();

            var participantEntities = requestDto.Participants.As<List<TeamWorkParticipantEntity>>();

            foreach (var item in participantEntities)
            {
                var staffEntity = staffInfoList.FirstOrDefault(p => p.AdminId == item.ParticipantId);

                if (staffEntity == null)
                {
                    throw new ArgumentException("参与人信息不正确");
                }

                item.ParticipantName = staffEntity.FullName;
                item.CompanyName = staffEntity.CompanyName;
                item.DepartmentName = staffEntity.DepartmentName;
                item.JobTitle = staffEntity.JobTitle;
            }

            entity.CreateAdminName = applicationContextService.Admin.FullName;
            entity.CreateAdminId = applicationContextService.Admin.AdminId;
            entity.TeamWorkCategoryId = categoryEntity.TeamWorkCategoryId;

            var result = this.teamWorkData.Add(entity).Result;

            if (result == null)
            {
                throw new ArgumentException("创建协同办公任务失败");
            }

            foreach (var item in participantEntities)
            {
                item.TeamWorkId = result.TeamWorkId;
            }

            if (!this.teamWorkParticipantData.Add(participantEntities).Result)
            {
                this.teamWorkData.Delete(result.TeamWorkId).Wait();
                throw new ArgumentException("添加协同办公任务参与人失败");
            }

            if (requestDto.Attachments != null && requestDto.Attachments.Any())
            {
                foreach (var attachment in requestDto.Attachments)
                {
                    TeamWorkAttachmentEntity attachmentEntity = attachment.As<TeamWorkAttachmentEntity>();
                    attachmentEntity.TeamWorkId = result.TeamWorkId;
                    this.teamWorkAttachmentData.Add(attachmentEntity).Wait();
                }
            }

            //// 创建聊天会话。
            //var thread = threadService.Create(new ThreadRequestDto
            //{
            //    Title = "协同办公",
            //    Subtitle = result.WorkTitle,
            //    Type = ThreadType.CustomerService,
            //    BusinessType = "TeamWork",
            //    ReferenceNumber = result.TeamWorkId.ToString(),
            //    ParticipantUserIds = participantEntities.Select(p => $"ADMIN-{p.ParticipantId}")
            //}, out _);

            //result.ThreadId = thread.ThreadId;

            return this.teamWorkData.Update(result).Result.TransformTo<TeamWorkDto>();
        }

        public TeamWorkDto Update(long teamWorkId, TeamWorkRequestDto requestDto)
        {
            if (!this.teamWorkCategoryData.Exists(requestDto.TeamWorkCategoryId).Result)
            {
                throw new ArgumentException("此协同办公分类不存在");
            }

            var oldEntity = this.teamWorkData.GetEntity(teamWorkId).Result;

            if (oldEntity == null)
            {
                throw new ArgumentException("此记录不存在");
            }

            if (oldEntity.WorkStatus == OAWorkStatus.Finished)
            {
                throw new ArgumentException("此工作已结束,无法继续操作");
            }

            if (oldEntity.WorkStatus == OAWorkStatus.Closed)
            {
                throw new ArgumentException("此工作已关闭,无法继续操作");
            }

            oldEntity.TeamWorkCategoryId = requestDto.TeamWorkCategoryId;
            oldEntity.WorkTitle = requestDto.WorkTitle;
            oldEntity.WorkContent = requestDto.WorkContent;

            return this.teamWorkData.Update(oldEntity).Result.As<TeamWorkDto>();
        }

        public TeamWorkDto UpdateFinish(long teamWorkId, RemarkRequestDto requestDto)
        {
            var entity = this.teamWorkData.GetEntity(teamWorkId).Result;

            if (entity == null)
            {
                throw new ArgumentException("此记录不存在");
            }

            if (entity.CreateAdminId != applicationContextService.Admin.AdminId && !applicationContextService.Admin.IsSystemAccount)
            {
                throw new ArgumentException("此任务仅支持发起人完成");
            }

            if (entity.WorkStatus == OAWorkStatus.Finished)
            {
                throw new ArgumentException("此工作已结束,无法继续操作");
            }

            if (entity.WorkStatus == OAWorkStatus.Closed)
            {
                throw new ArgumentException("此工作已关闭,无法继续操作");
            }

            //// 关闭聊天会话
            //if (entity.ThreadId != null)
            //{
            //    threadService.Close(entity.ThreadId.Value, new ThreadCloseRequestDto
            //    {
            //        ReasonCode = ThreadCloseReasonCode.Completed,
            //        ReasonText = "原业务被标记为完成。",
            //        OnlyCloseThread = true
            //    });
            //}

            entity.FinishRemark = requestDto.Remark;
            entity.FinishTime = DateTime.Now;
            entity.FinishAdminName = applicationContextService.Admin.FullName;
            entity.WorkStatus = OAWorkStatus.Finished;

            return this.teamWorkData.Update(entity).Result.As<TeamWorkDto>();
        }

        public TeamWorkDto UpdateClose(long teamWorkId, RemarkRequestDto requestDto)
        {
            var entity = this.teamWorkData.GetEntity(teamWorkId).Result;

            if (entity == null)
            {
                throw new ArgumentException("此记录不存在");
            }

            if (entity.CreateAdminId != applicationContextService.Admin.AdminId && !applicationContextService.Admin.IsSystemAccount)
            {
                throw new ArgumentException("此任务仅支持发起人完成");
            }

            if (entity.WorkStatus == OAWorkStatus.Finished)
            {
                throw new ArgumentException("此工作已结束,无法继续操作");
            }

            if (entity.WorkStatus == OAWorkStatus.Closed)
            {
                throw new ArgumentException("此工作已关闭,无法继续操作");
            }

            //// 关闭聊天会话
            //if (entity.ThreadId != null)
            //{
            //    threadService.Close(entity.ThreadId.Value, new ThreadCloseRequestDto
            //    {
            //        ReasonCode = ThreadCloseReasonCode.Unset,
            //        ReasonText = "原业务被关闭。",
            //        OnlyCloseThread = true
            //    });
            //}

            entity.CloseRemark = requestDto.Remark;
            entity.CloseTime = DateTime.Now;
            entity.CloseAdminName = applicationContextService.Admin.FullName;
            entity.WorkStatus = OAWorkStatus.Closed;

            return this.teamWorkData.Update(entity).Result.As<TeamWorkDto>();
        }

        public bool Delete(long teamWorkId)
        {
            var entity = this.teamWorkData.GetEntity(teamWorkId).Result;

            if (entity == null)
            {
                throw new ObjectNotFoundException();
            }

            //// 关闭聊天会话
            //if (entity.ThreadId != null)
            //{
            //    threadService.Close(entity.ThreadId.Value, new ThreadCloseRequestDto
            //    {
            //        ReasonCode = ThreadCloseReasonCode.Unset,
            //        ReasonText = "原业务被删除。",
            //        OnlyCloseThread = true
            //    });
            //}

            this.teamWorkAttachmentData.DeleteBatch(entity.TeamWorkId).Wait();
            this.teamWorkParticipantData.DeleteBatch(entity.TeamWorkId).Wait();
            this.teamWorkReplyData.DeleteBatch(entity.TeamWorkId).Wait();

            return this.teamWorkData.Delete(teamWorkId).Result;
        }

        public TeamWorkViewDto GetEntity(long teamWorkId)
        {
            return this.teamWorkData.GetEntity(teamWorkId).GetAwaiter().GetResult().As<TeamWorkViewDto>();
        }

        public IEnumerable<TeamWorkViewDto> GetList(string teamWorkCategoryCode, DateTime? start, DateTime? end)
        {
            return this.teamWorkData.GetList(teamWorkCategoryCode, start, end).GetAwaiter().GetResult().As<IEnumerable<TeamWorkViewDto>>();
        }

        public int GetProcessingCount(long participantId, string teamWorkCategoryCode)
        {
            return this.teamWorkData.GetProcessingCount(participantId, teamWorkCategoryCode).GetAwaiter().GetResult();
        }

        public PageableList<TeamWorkViewDto> Query(string referenceNo, string workTitle, string teamWorkCategoryCode, OAWorkStatus? workStatus, DateTime? start, DateTime? end, int pageIndex, int pageSize)
        {
            var (list, count) = this.teamWorkData.Query(referenceNo, workTitle, teamWorkCategoryCode, workStatus, start, end, pageIndex, pageSize).GetAwaiter().GetResult();

            return new PageableList<TeamWorkViewDto>
            {
                Items = list.As<IEnumerable<TeamWorkViewDto>>(),
                Count = count,
                PageIndex = pageIndex,
                PageSize = pageSize
            };
        }

        public PageableList<TeamWorkViewDto> Query(long participantId, string teamWorkCategoryCode, OAWorkStatus? workStatus, DateTime? start, DateTime? end, int pageIndex, int pageSize)
        {
            var (list, count) = this.teamWorkData.Query(participantId, teamWorkCategoryCode, workStatus, start, end, pageIndex, pageSize).GetAwaiter().GetResult();

            return new PageableList<TeamWorkViewDto>
            {
                Items = list.As<IEnumerable<TeamWorkViewDto>>(),
                Count = count,
                PageIndex = pageIndex,
                PageSize = pageSize
            };
        }
        #endregion

        #region 获取参与人列表
        public IEnumerable<TeamWorkParticipantDto> GetParticipantList(long teamWorkId)
        {
            var list = this.teamWorkParticipantData.GetList(teamWorkId).GetAwaiter().GetResult();
            return list.As<IEnumerable<TeamWorkParticipantDto>>();
        }
        #endregion

        #region 追加协同办公参与者
        public IEnumerable<TeamWorkParticipantDto> AppendParticipant(long teamWorkId, List<TeamWorkParticipantRequestDto> requestDtos)
        {
            var teamWorkEntity = this.teamWorkData.GetEntity(teamWorkId).GetAwaiter().GetResult();

            if (teamWorkEntity == null)
            {
                throw new ArgumentException("协同办公任务不存在");
            }

            if (teamWorkEntity.WorkStatus == OAWorkStatus.Finished)
            {
                throw new ArgumentException("此工作已结束,无法继续操作");
            }

            if (teamWorkEntity.WorkStatus == OAWorkStatus.Closed)
            {
                throw new ArgumentException("此工作已关闭,无法继续操作");
            }

            var list = this.teamWorkParticipantData.GetList(teamWorkId).GetAwaiter().GetResult();
            var staffList = requestDtos.Select(p => p.ParticipantId).ToList();
            foreach (long item in staffList)
            {
                if (list.Any(p => p.ParticipantId == item))
                {
                    throw new ArgumentException(string.Format("【{0}】 已是任务参与人，无需重复添加", list.Single(p => p.ParticipantId == item).ParticipantName));
                }
            }

            var staffInfoList = this.staffOrganizationMappingRecordData.GetList(staffList.ToArray()).GetAwaiter().GetResult();
            if (!staffInfoList.Any())
            {
                throw new ArgumentException("参与人列表未获取到任何信息");
            }
            var participantEntities = requestDtos.As<List<TeamWorkParticipantEntity>>();
            foreach (var item in participantEntities)
            {
                var staffEntity = staffInfoList.SingleOrDefault(p => p.AdminId == item.ParticipantId);
                if (staffEntity == default(StaffOrganizationMappingRecordEntity))
                {
                    throw new ArgumentException("参与人信息不正确");
                }
                item.ParticipantName = staffEntity.FullName;
                item.CompanyName = staffEntity.CompanyName;
                item.DepartmentName = staffEntity.DepartmentName;
                item.JobTitle = staffEntity.JobTitle;
            }

            var participantResult = this.teamWorkParticipantData.Add(participantEntities).GetAwaiter().GetResult();
            if (!participantResult)
            {
                throw new ArgumentException("追加协同办公参与人失败");
            }
            var result = this.teamWorkParticipantData.GetList(teamWorkId).GetAwaiter().GetResult();
            return result.As<IEnumerable<TeamWorkParticipantDto>>();
        }
        #endregion

        #region 删除协同办公参与者
        public bool DeleteParticipant(long teamWorkParticipantId)
        {
            if (!this.teamWorkParticipantData.Exists(teamWorkParticipantId).GetAwaiter().GetResult())
            {
                throw new ArgumentException("此记录不存在");
            }
            var participantEntity = this.teamWorkParticipantData.GetEntity(teamWorkParticipantId).GetAwaiter().GetResult();
            var teamWorkEntity = this.teamWorkData.GetEntity(participantEntity.TeamWorkId).GetAwaiter().GetResult();
            if (teamWorkEntity.WorkStatus == OAWorkStatus.Finished)
            {
                throw new ArgumentException("此工作已结束,无法继续操作");
            }

            if (teamWorkEntity.WorkStatus == OAWorkStatus.Closed)
            {
                throw new ArgumentException("此工作已关闭,无法继续操作");
            }
            if (teamWorkEntity.CreateAdminId == participantEntity.ParticipantId)
            {
                throw new ArgumentException("无法移除发起人");
            }
            if (1 == participantEntity.ParticipantId)
            {
                throw new ArgumentException("无法移除总经理");
            }
            return this.teamWorkParticipantData.Delete(teamWorkParticipantId).GetAwaiter().GetResult();
        }
        #endregion

        #region 获取协同办公回复列表
        public IEnumerable<TeamWorkReplyDto> GetReplyList(long teamWorkId)
        {
            var list = this.teamWorkReplyData.GetList(teamWorkId).GetAwaiter().GetResult();

            return list.As<IEnumerable<TeamWorkReplyDto>>();
        }

        public TeamWorkReplyDto AddReply(TeamWorkReplyRequestDto teamWorkReplyRequestDto)
        {
            var teamWorkEntity = this.teamWorkData.GetEntity(teamWorkReplyRequestDto.TeamWorkId).GetAwaiter().GetResult();
            if (teamWorkEntity == null)
            {
                throw new ArgumentException("此协同办公不存在");
            }

            if (teamWorkEntity.WorkStatus == OAWorkStatus.Finished)
            {
                throw new ArgumentException("此工作已结束,无法继续回复");
            }

            if (teamWorkEntity.WorkStatus == OAWorkStatus.Closed)
            {
                throw new ArgumentException("此工作已关闭,无法继续回复");
            }
            if (teamWorkReplyRequestDto.ReplyType != OATeamWorkReplyType.Text && string.IsNullOrWhiteSpace(teamWorkReplyRequestDto.FileAddress))
            {
                throw new ArgumentException("非文本回复，文件地址不允许为空");
            }
            long? attachmentId = null;
            if (teamWorkReplyRequestDto.ReplyType != OATeamWorkReplyType.Text && !string.IsNullOrWhiteSpace(teamWorkReplyRequestDto.FileAddress))
            {
                string suffix = teamWorkReplyRequestDto.FileAddress.Substring(teamWorkReplyRequestDto.FileAddress.LastIndexOf("."));
                if (string.IsNullOrWhiteSpace(suffix))
                {
                    throw new ArgumentException("回复附件类型错误");
                }
                Regex regexImage = new Regex("(.gif|.jpeg|.png|.jpg|.bmp)");
                if (regexImage.Match(suffix).Success && teamWorkReplyRequestDto.ReplyType != OATeamWorkReplyType.Image)
                {
                    teamWorkReplyRequestDto.ReplyType = OATeamWorkReplyType.Image;
                }
                Regex regexDoc = new Regex("(.doc|.docx)");
                if (regexDoc.Match(suffix).Success && teamWorkReplyRequestDto.ReplyType != OATeamWorkReplyType.Doc)
                {
                    teamWorkReplyRequestDto.ReplyType = OATeamWorkReplyType.Doc;
                }
                Regex regexExcel = new Regex("(.xls|.xlsx)");
                if (regexExcel.Match(suffix).Success && teamWorkReplyRequestDto.ReplyType != OATeamWorkReplyType.Excel)
                {
                    teamWorkReplyRequestDto.ReplyType = OATeamWorkReplyType.Excel;
                }
                Regex regexPPT = new Regex("(.ppt|.pptx)");
                if (regexPPT.Match(suffix).Success && teamWorkReplyRequestDto.ReplyType != OATeamWorkReplyType.PPT)
                {
                    teamWorkReplyRequestDto.ReplyType = OATeamWorkReplyType.PPT;
                }
                if (!string.IsNullOrWhiteSpace(suffix) && teamWorkReplyRequestDto.ReplyType == OATeamWorkReplyType.Share)
                {
                    throw new ArgumentException("分享类型，暂不支持");
                }
                var attachment = new TeamWorkAttachmentEntity
                {
                    FileAddress = teamWorkReplyRequestDto.FileAddress,
                    FileSource = OATeamWorkFileSourceType.Reply,
                    TeamWorkId = teamWorkEntity.TeamWorkId
                };
                var attachmentResult = this.teamWorkAttachmentData.Add(attachment).GetAwaiter().GetResult();
                if (attachmentResult == null)
                {
                    throw new ArgumentException("回复附件添加失败");
                }
                attachmentId = attachmentResult.TeamWorkAttachmentId;
            }

            var list = this.teamWorkParticipantData.GetList(teamWorkReplyRequestDto.TeamWorkId).GetAwaiter().GetResult();
            if (!list.Any(p => p.ParticipantId == applicationContextService.Admin.AdminId))
            {
                throw new ArgumentException("你不是任务参与人，无权回复信息");
            }

            var replyEntity = teamWorkReplyRequestDto.As<TeamWorkReplyEntity>();
            replyEntity.ParticipantId = applicationContextService.Admin.AdminId;
            replyEntity.TeamWorkAttachmentId = attachmentId;
            var replyResult = this.teamWorkReplyData.Add(replyEntity).GetAwaiter().GetResult();
            if (replyResult == null)
            {
                throw new ArgumentException("回复失败");
            }

            return replyResult.As<TeamWorkReplyDto>();
        }
        #endregion
    }
}